"use strict";
require( '../../../config' );
var assert = require('assert'),
    sandbox = require('../../../../app/components/backend/util/sandbox'),
    sinon   = require('sinon'),  sinonSandbox,
    Promise  = require('bluebird'),
    weixinuserDao = require('../../../../app/components/backend/db').weixinuser,
    weixinuserModel = require('../../../../app/components/backend/db/models/weixinuser'),
    exchangeService = require('../../../../app/components/backend/service').exchange,
    util = require('../../../../app/components/backend/util'),
    weixin = require('../../../../app/components/backend/service/weixin'),
    mockApplicant = {},
    weixinuserDaoStub = {},
    dueDate = Date.now() + (10 * 24 * 3600 * 1000 + 3600), // 保证有10天才会过期
    overDueDate = Date.now() - (10 * 24 * 3600 * 1000 + 3600); // 已经过期10天

describe('app/components/backend/service/exchange', function () {
  // 测试前置处理
  beforeEach(function () {

    // 初始化sinon
    sinonSandbox = sinon.sandbox.create();
    mockApplicant = new weixinuserModel({
      openid: 'xxxx',
      due_date: dueDate,
      point: 10,
      nickname: 'neil'
    });
    weixinuserDaoStub = sinonSandbox.stub(weixinuserDao, "findByOpenId")
      .withArgs('xxxx')
      .returns(Promise.resolve(mockApplicant));
    sinonSandbox.stub(mockApplicant, "save").returns(Promise.resolve());
    return Promise.resolve();
  });

  // 测试后置处理
  afterEach(function() {

    // 复位
    if (sinonSandbox) sinonSandbox.restore();
    util.config.exchange_rate.point_vpn_time = 1;
    mockApplicant.openid = 'xxxx';
    mockApplicant.due_date = dueDate;
  });
  describe('point换时间', function () {
    it('[service.exchange.p2t.Nor.01].1 point 兑换整数时间. 点数不足', function () {
      var spyEmit = sinonSandbox.spy(sandbox, 'emit');
      return Promise.resolve(sandbox.emit(sandbox.MSG.EXCH_POINT_TO_VPN_TIME, {openid:'xxxx', dates: 999}))
        .delay(100).then(function () {
          checkHelper(spyEmit, 0, -10, 10);
          return Promise.resolve();
        });
    });

    it('[service.exchange.p2t.Nor.02].1 point 兑换整数时间. 点数足够', function () {
      var spyEmit = sinonSandbox.spy(sandbox, 'emit');
      return Promise.resolve(sandbox.emit(sandbox.MSG.EXCH_POINT_TO_VPN_TIME, {openid:'xxxx', dates: 8}))
        .delay(100).then(function () {
          checkHelper(spyEmit, 2, -8, 8);
          return Promise.resolve();
        });
    });

    it('[service.exchange.p2t.Nor.03].1 point 兑换非整数时间. 点数不足够', function () {
      var spyEmit = sinonSandbox.spy(sandbox, 'emit');
      util.config.exchange_rate.point_vpn_time = 1/3; // 3 point -> 1 date
      return Promise.resolve(sandbox.emit(sandbox.MSG.EXCH_POINT_TO_VPN_TIME, {openid:'xxxx', dates: 999}))
        .delay(100).then(function () {
          checkHelper(spyEmit, 1, -9, 3);
          return Promise.resolve();
        });
    });

    it('[service.exchange.p2t.Nor.04].1 point 兑换非整数时间. 点数足够', function () {
      var spyEmit = sinonSandbox.spy(sandbox, 'emit');
      util.config.exchange_rate.point_vpn_time = 1/3; // 3 point -> 1 date
      return Promise.resolve(sandbox.emit(sandbox.MSG.EXCH_POINT_TO_VPN_TIME, {openid:'xxxx', dates: 1}))
        .delay(100).then(function () {
          checkHelper(spyEmit, 7, -3, 1);
          return Promise.resolve();
        });
    });

    it('[service.exchange.p2t.Nor.05].兑换0天', function () {
      var spyEmit = sinonSandbox.spy(sandbox, 'emit');
      return Promise.resolve(sandbox.emit(sandbox.MSG.EXCH_POINT_TO_VPN_TIME, {openid:'xxxx', dates: 0}))
        .delay(100).then(function () {
          assert.equal(mockApplicant.point, 10);
          assert.equal(mockApplicant.due_date, dueDate);
          assert.equal(spyEmit.secondCall, null);
          return Promise.resolve();
        });
    });
  });

  describe('时间换point', function () {
    it('[service.exchange.t2p.Nor.01].过期用户', function () {
      var spyEmit = sinonSandbox.spy(sandbox, 'emit');

      // 返回一个过期的用户
      mockApplicant.openid = 'yyyy';
      mockApplicant.due_date = overDueDate;
      weixinuserDaoStub.withArgs('yyyy').returns(Promise.resolve(mockApplicant));
      return Promise.resolve(sandbox.emit(sandbox.MSG.EXCH_POINT_TO_VPN_TIME, {openid:'yyyy', dates: -999}))
        .delay(100).then(function () {
          assert.equal(mockApplicant.point, 10);
          assert.equal(mockApplicant.due_date, overDueDate);
          assert.equal(spyEmit.secondCall, null);
          return Promise.resolve();
        });
    });

    it('[service.exchange.t2p.Nor.02].1天兑换整数point.天数足够', function () {
      var spyEmit = sinonSandbox.spy(sandbox, 'emit');
      return Promise.resolve(sandbox.emit(sandbox.MSG.EXCH_POINT_TO_VPN_TIME, {openid:'xxxx', dates: -2}))
        .delay(100).then(function () {
          checkHelper(spyEmit, 12, 2, -2);
          return Promise.resolve();
        });
    });

    it('[service.exchange.t2p.Nor.03].1天兑换整数point.天数不足', function () {
      var spyEmit = sinonSandbox.spy(sandbox, 'emit');
      return Promise.resolve(sandbox.emit(sandbox.MSG.EXCH_POINT_TO_VPN_TIME, {openid:'xxxx', dates: -999}))
        .delay(100).then(function () {
          checkHelper(spyEmit, 20, 10, -10);
          return Promise.resolve();
        });
    });

    it('[service.exchange.t2p.Nor.04].1天兑换非整数point.天数足够', function () {
      var spyEmit = sinonSandbox.spy(sandbox, 'emit');

      // 3天兑换1point
      util.config.exchange_rate.point_vpn_time = 3/1;
      return Promise.resolve(sandbox.emit(sandbox.MSG.EXCH_POINT_TO_VPN_TIME, {openid:'xxxx', dates: -5}))
        .delay(100).then(function () {
          checkHelper(spyEmit, 11, 1, -3);
          return Promise.resolve();
        });
    });

    it('[service.exchange.t2p.Nor.05].1天兑换非整数point.天数不足', function () {
      var spyEmit = sinonSandbox.spy(sandbox, 'emit');

      // 3天兑换1point
      util.config.exchange_rate.point_vpn_time = 3/1;
      return Promise.resolve(sandbox.emit(sandbox.MSG.EXCH_POINT_TO_VPN_TIME, {openid:'xxxx', dates: -12}))
        .delay(100).then(function () {
          checkHelper(spyEmit, 13, 3, -9);
          return Promise.resolve();
        });
    });
  });
  describe('特殊情况处理', function () {
    it('[service.exchange.Err.01].msg为空', function () {
      var spyEmit = sinonSandbox.spy(sandbox, 'emit');
      return Promise.resolve(sandbox.emit(sandbox.MSG.EXCH_POINT_TO_VPN_TIME, {}))
        .delay(100).then(function () {
          assert.equal(mockApplicant.point, 10);
          assert.equal(mockApplicant.due_date, dueDate);
          assert.equal(spyEmit.secondCall, null);
          return Promise.resolve();
        });
    });

    it('[service.exchange.Err.02].msg时间不是一个数字', function () {
      var spyEmit = sinonSandbox.spy(sandbox, 'emit');
      return Promise.resolve(sandbox.emit(sandbox.MSG.EXCH_POINT_TO_VPN_TIME, {openid:'xxxx', dates: 'xxx'}))
        .delay(100).then(function () {
          assert.equal(mockApplicant.point, 10);
          assert.equal(mockApplicant.due_date, dueDate);
          assert.equal(spyEmit.secondCall, null);
          return Promise.resolve();
        });
    });

    it('[service.exchange.Err.03].openid查询不到weixin用户', function () {
      var spyEmit = sinonSandbox.spy(sandbox, 'emit');
      weixinuserDaoStub.withArgs('zzzz').returns(Promise.resolve(null));
      return Promise.resolve(sandbox.emit(sandbox.MSG.EXCH_POINT_TO_VPN_TIME, {openid:'zzzz', dates: -8}))
        .delay(100).then(function () {
          assert.equal(mockApplicant.point, 10);
          assert.equal(mockApplicant.due_date, dueDate);
          assert.equal(spyEmit.secondCall, null);
          return Promise.resolve();
        });
    });

    it('[service.exchange.Err.04].openid查询不到weixin用户', function () {
      var spyEmit = sinonSandbox.spy(sandbox, 'emit');
      weixinuserDaoStub.withArgs('zzzz').returns(Promise.resolve(null));
      return Promise.resolve(sandbox.emit(sandbox.MSG.EXCH_POINT_TO_VPN_TIME, {openid:'zzzz', dates: -8}))
        .delay(100).then(function () {
          assert.equal(mockApplicant.point, 10);
          assert.equal(mockApplicant.due_date, dueDate);
          assert.equal(spyEmit.secondCall, null);
          return Promise.resolve();
        });
    });

    it('[service.exchange.Err.05].openid查询出错', function () {
      var spyEmit = sinonSandbox.spy(sandbox, 'emit');
      weixinuserDaoStub.withArgs('zzzz').returns(Promise.reject());
      return Promise.resolve(sandbox.emit(sandbox.MSG.EXCH_POINT_TO_VPN_TIME, {openid:'zzzz', dates: -8}))
        .delay(100).then(function () {
          assert.equal(mockApplicant.point, 10);
          assert.equal(mockApplicant.due_date, dueDate);
          assert.equal(spyEmit.secondCall, null);
          return Promise.resolve();
        });
    });
  });
});

function checkHelper(spy, remainPoint, point, amount) {
  assert.equal(mockApplicant.point, remainPoint);
  assert.equal(mockApplicant.due_date, dueDate + amount * 1000 * 3600 * 24);
  assert.equal(spy.secondCall.args[0], util.sandbox.MSG.LOG_POINTHISTORY);
  assert.equal(spy.secondCall.args[1].triggered_by, 'xxxx');
  assert.equal(spy.secondCall.args[1].triggered_by_name, 'neil');
  assert.equal(spy.secondCall.args[1].awarded_to, '');
  assert.equal(spy.secondCall.args[1].awarded_to_name, '');
  assert.ok(0 < Date.now() - spy.secondCall.args[1].create_time < 2000);
  assert.equal(spy.secondCall.args[1].action_type, 'exchange');
  assert.equal(spy.secondCall.args[1].point, point);
  assert.equal(spy.secondCall.args[1].exchange.exchange_type, util.sandbox.MSG.EXCH_POINT_TO_VPN_TIME);
  assert.equal(spy.secondCall.args[1].exchange.amount, amount);
}